using System;
using System.Collections.Generic;
using System.Text;
using RaisingStudio.Data.Common.Factories;
using System.Data.Common;

namespace RaisingStudio.Data.Common.Managers
{
    public sealed class ObjectAccessorManager
    {
        #region Instance
        //public static readonly ObjectAccessorManager Instance = new ObjectAccessorManager();
        private static volatile ObjectAccessorManager _instance = null;
        public static ObjectAccessorManager Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (typeof(ObjectAccessorManager))
                    {
                        if (_instance == null)
                        {
                            _instance = new ObjectAccessorManager();
                        }
                    }
                }
                return _instance;
            }
        }
        #endregion

        private Dictionary<System.Type, IObjectAccessor> _objectAccessors = new Dictionary<System.Type, IObjectAccessor>();

        public Dictionary<System.Type, IObjectAccessor> ObjectAccessors
        {
            get { return _objectAccessors; }
            set { _objectAccessors = value; }
        }

        private Dictionary<System.Type, Dictionary<string, System.Type>> _propertyTypes = new Dictionary<System.Type, Dictionary<string, System.Type>>();

        public Dictionary<System.Type, Dictionary<string, System.Type>> PropertyTypes
        {
            get { return _propertyTypes; }
            set { _propertyTypes = value; }
        }


        private ObjectAccessorFactory _objectAccessorFactory = new ObjectAccessorFactory();
     
        private ObjectAccessorManager()
        {

        }

        public IObjectAccessor GetObjectAccessor(System.Type type)
        {
            return this._objectAccessors[type];
        }

        public IObjectAccessor GetObjectAccessor(System.Type type, string[] propertyNames)
        {
            if (!this._objectAccessors.ContainsKey(type))
            {
                Dictionary<string, System.Type> propertyTypes;
                IObjectAccessor objectAccessor = this._objectAccessorFactory.CreateObjectAccessor(type, propertyNames, out propertyTypes);
                this._objectAccessors[type] = objectAccessor;
                this._propertyTypes[type] = propertyTypes;
                return objectAccessor;
            }
            else
            {
                return this._objectAccessors[type];
            }
        }

        public System.Type GetPropertyType(System.Type type, string propertyName)
        {
            if(this._propertyTypes.ContainsKey(type))
            {
                return this._propertyTypes[type][propertyName];
            }
            else
            {
                return null;
            }
        }

        public IObjectAccessor GetObjectAccessor(System.Type type, DataColumnMappingCollection columnMappings)
        {
            if (!this._objectAccessors.ContainsKey(type))
            {
                string[] propertyNames = GetPropertyNames(columnMappings);
                return GetObjectAccessor(type, propertyNames);
            }
            else
            {
                return this._objectAccessors[type];
            }
        }

        private string[] GetPropertyNames(DataColumnMappingCollection columnMappings)
        {
            string[] propertyNames = new string[columnMappings.Count];
            for (int i = 0; i < columnMappings.Count; i++)
            {
                propertyNames[i] = columnMappings[i].DataSetColumn;
            }
            return propertyNames;
        }

        public IObjectAccessor GetObjectAccessor(System.Type type, Dictionary<string, DataColumnDefinition> columns)
        {
            if (!this._objectAccessors.ContainsKey(type))
            {
                string[] propertyNames = GetPropertyNames(columns);
                return GetObjectAccessor(type, propertyNames);
            }
            else
            {
                return this._objectAccessors[type];
            }
        }

        private string[] GetPropertyNames(Dictionary<string, DataColumnDefinition> columns)
        {
            string[] propertyNames = new string[columns.Count];
            columns.Keys.CopyTo(propertyNames, 0);
            return propertyNames;
        }
    }
}
